package com.ctshk.rpc.guide.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.*;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.rpc.guide.dto.GuideCollarSchedulingDTO;
import com.ctshk.rpc.guide.dto.GuideCollarSchedulingExcelDTO;
import com.ctshk.rpc.guide.dto.GuideCollarSchedulingListDTO;
import com.ctshk.rpc.guide.dto.GuideCollarSchedulingQueryDTO;
import com.ctshk.rpc.guide.entity.GuideCollar;
import com.ctshk.rpc.guide.entity.GuideCollarMonthlyLeave;
import com.ctshk.rpc.guide.entity.GuideCollarScheduling;
import com.ctshk.rpc.guide.mapper.GuideCollarMapper;
import com.ctshk.rpc.guide.mapper.GuideCollarMonthlyLeaveMapper;
import com.ctshk.rpc.guide.mapper.GuideCollarSchedulingMapper;
import com.ctshk.rpc.guide.req.*;
import com.ctshk.rpc.guide.service.IGuideCollarSchedulingService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 排班管理 服务实现类
 * </p>
 *
 * @author 谢诗宏
 * @since 2021-03-03
 */
@DubboService
public class GuideCollarSchedulingServiceImpl extends ServiceImpl<GuideCollarSchedulingMapper, GuideCollarScheduling> implements IGuideCollarSchedulingService {

    @Autowired
    private GuideCollarMapper guideCollarMapper;
    @Autowired
    private GuideCollarMonthlyLeaveMapper guideCollarMonthlyLeaveMapper;

    public static Long WORKID1 = 1369094686320492547L;//全陪
    public static String WORKID1_NAME = "全陪";
    public static Long WORKID2 = 1369094730373267457L;//送团
    public static String WORKID2_NAME = "送团";
    public static Long WORKID3 = 1369105497684312065L;//茶会
    public static String WORKID3_NAME = "茶会";
    public static Long WORKID4 = 1369095049282977794L;//休假（月假）
    public static String WORKID4_NAME = "休假";
    public static Long WORKID5 = 1394215898811904001L;//年假
    public static String WORKID5_NAME = "年假";
    public static Long WORKID6 = 1394215903190757378L;//劳假
    public static String WORKID6_NAME = "劳假";

    /**
     * 新增个人排班
     * 该函数谨慎修改
     *
     * @param req
     * @param tokenUser
     * @param flagea    标记是月初自动调用还是手动调用
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result add(GuideCollarSchedulingAddReq req, TokenUser tokenUser, boolean flagea) {
        GuideCollarScheduling guideCollarScheduling = EntityUtil.copy(req, GuideCollarScheduling.class);
        LocalDateTime now = LocalDateTime.now();
        guideCollarScheduling.setCreateId(tokenUser.getId());
        guideCollarScheduling.setGmtCreate(now);
        guideCollarScheduling.setGmtModified(now);
        guideCollarScheduling.setRemark(req.getRemark());
        guideCollarScheduling.setModifiedId(tokenUser.getId());
        guideCollarScheduling.setIsDeleted(IsDeletedCode.NO.getCode());
        int days = Period.between(req.getSchedulingDateBegin(), req.getSchedulingDateEnd()).getDays();
        GuideCollar gc = guideCollarMapper.selectById(req.getGuideCollarId());
        if (gc != null) {
            int workDays = Period.between(gc.getEntryTime(), LocalDate.now()).getDays();
            if (workDays > gc.getContractPeriod() * 365) {
                return Result.failed(SystemError.GUIDE_410011);
            }
            //按日期安排
            if (req.getArrangementType() == GuideCollarSchedulingType.DATE.getCode()) {
                int count = 0;
                out:
                for (int i = 0; i <= days; i++) {
                    LocalDate newDate = req.getSchedulingDateBegin().plusDays(i);
                    QueryWrapper<GuideCollarScheduling> queryWrapper = new QueryWrapper<>();
                    queryWrapper.lambda().eq(GuideCollarScheduling::getSchedulingDate, newDate)
                            .eq(GuideCollarScheduling::getIsDeleted, IsDeletedCode.NO.getCode())
                            .eq(GuideCollarScheduling::getGuideCollarId, req.getGuideCollarId());
                    List<GuideCollarScheduling> guideCollarSchedulingList = baseMapper.selectList(queryWrapper);
                    //如果当日没有安排，则直接排班
                    if (CollectionUtils.isEmpty(guideCollarSchedulingList)) {
                        guideCollarScheduling.setId(IdWorker.getId());
                        guideCollarScheduling.setSchedulingDate(newDate);
                        if (!flagea) {
                            //安排成功减扣导领的假期
                            if (guideCollarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                                if (!minusVacation(guideCollarScheduling, gc, 1)) {
                                    continue;
                                }
                            } else {
                                if (!minusVacation(guideCollarScheduling, gc, 0.5f)) {
                                    continue;
                                }
                            }
                        }
                        count += baseMapper.insert(guideCollarScheduling);
                    } else if (guideCollarSchedulingList.size() == 1) {
                        //如果当前只有一条记录说明可能出现（上午|下午|全天）
                        GuideCollarScheduling collarScheduling = guideCollarSchedulingList.get(0);
                        Integer workingHours = collarScheduling.getWorkingHours();
                        //如果不是不能修改的三种类型那么我们直接把这条记录修改
                        if (!WORKID1.equals(collarScheduling.getWorkTypeId()) && !WORKID2.equals(collarScheduling.getWorkTypeId())
                                && !WORKID3.equals(collarScheduling.getWorkTypeId())) {
                            //匹配上能修改的就修改 否则就新增
                            if (workingHours == req.getWorkingHours()) {
                                collarScheduling.setWorkingHours(req.getWorkingHours());
                                collarScheduling.setWorkTypeId(req.getWorkTypeId());
                                collarScheduling.setWorkTypeName(req.getWorkTypeName());
                                collarScheduling.setRemark(req.getRemark());
                                if (!flagea) {
                                    float v = setMinusVacation(req, collarScheduling, gc);
                                    if (v > 0) {
                                        //实际减扣不足跳过这次工作安排
                                        if (!minusVacation(collarScheduling, gc, v)) {
                                            continue;
                                        }
                                    }
                                }
                                count += baseMapper.updateById(collarScheduling);
                            } else {
                                //现有安排是全天的
                                if (workingHours == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                                    //新增半天  原来有一个全天就把全天修改成半天  在新增一个半天的
                                    guideCollarScheduling.setSchedulingDate(newDate);
                                    guideCollarScheduling.setId(IdWorker.getId());
                                    if (!flagea) {
                                        //安排成功减扣导领的假期
                                        if (guideCollarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                                            if (!minusVacation(guideCollarScheduling, gc, 1)) {
                                                continue;
                                            }
                                        } else {
                                            if (!minusVacation(guideCollarScheduling, gc, 0.5f)) {
                                                continue;
                                            }
                                        }
                                    }
                                    int insert = baseMapper.insert(guideCollarScheduling);
                                    if (insert > 0) {
                                        //根据反方向修改   如果新增的是上午就修改成下午，如果是下午就修改成上午
                                        int hours = guideCollarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.FORENOON.getCode()
                                                ? GuideCollarSchedulingWorkHours.AFTERNOON.getCode() :
                                                GuideCollarSchedulingWorkHours.FORENOON.getCode();
                                        collarScheduling.setWorkingHours(hours);
                                        collarScheduling.setWorkTypeId(req.getWorkTypeId());
                                        collarScheduling.setWorkTypeName(req.getWorkTypeName());
                                        collarScheduling.setRemark(req.getRemark());
                                        if (!flagea) {
                                            float v = setMinusVacation(req, collarScheduling, gc);
                                            if (v > 0) {
                                                //实际减扣不足跳过这次工作安排
                                                if (!minusVacation(collarScheduling, gc, v)) {
                                                    continue;
                                                }
                                            }
                                        }
                                        count += baseMapper.updateById(collarScheduling);
                                    }
                                } else {
                                    //预计安排的是全天的 直接修改成全天的
                                    if (req.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                                        collarScheduling.setWorkingHours(req.getWorkingHours());
                                        collarScheduling.setWorkTypeName(req.getWorkTypeName());
                                        collarScheduling.setRemark(req.getRemark());
                                        if (!flagea) {
                                            float v = setMinusVacation(req, collarScheduling, gc);
                                            if (v > 0) {
                                                //实际减扣不足跳过这次工作安排
                                                if (!minusVacation(collarScheduling, gc, v)) {
                                                    continue;
                                                }
                                            }
                                        }
                                        count += baseMapper.updateById(collarScheduling);
                                    } else {
                                        //都不是全天  而且是错开的 就直接新增
                                        guideCollarScheduling.setSchedulingDate(newDate);
                                        guideCollarScheduling.setId(IdWorker.getId());
                                        if (!flagea) {
                                            //安排成功减扣导领的假期
                                            if (guideCollarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                                                if (!minusVacation(guideCollarScheduling, gc, 1)) {
                                                    continue;
                                                }
                                            } else {
                                                if (!minusVacation(guideCollarScheduling, gc, 0.5f)) {
                                                    continue;
                                                }
                                            }
                                        }
                                        count += baseMapper.insert(guideCollarScheduling);
                                    }
                                }
                            }
                        } else {
                            //如果是不能修改的类型那么说明我们只能新增错开的空白日期
                            //如果请求的类型不是全天的并且请求的类型和现有类型不相等说明是错开的，直接添加
                            if (req.getWorkingHours() != GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode() && req.getWorkingHours() != workingHours) {
                                guideCollarScheduling.setSchedulingDate(newDate);
                                guideCollarScheduling.setId(IdWorker.getId());
                                if (!flagea) {
                                    //安排成功减扣导领的假期
                                    if (guideCollarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                                        if (!minusVacation(guideCollarScheduling, gc, 1)) {
                                            continue;
                                        }
                                    } else {
                                        if (!minusVacation(guideCollarScheduling, gc, 0.5f)) {
                                            continue;
                                        }
                                    }
                                }
                                count += baseMapper.insert(guideCollarScheduling);
                            }
                        }
                    } else {
                        //如果当前有两条记录说明可能出现（上午和下午）
                        //如果当前请求安排的为全天就需要判断是否有不能改的三种类型，如果没有直接删除数据库的两天记录，新增一条安排的记录
                        if (req.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                            boolean flage = true;
                            for (GuideCollarScheduling item : guideCollarSchedulingList) {
                                if (WORKID1.equals(item.getWorkTypeId())
                                        || WORKID2.equals(item.getWorkTypeId())
                                        || WORKID3.equals(item.getWorkTypeId())) {
                                    flage = false;
                                    break;//有一条不能修改就结束
                                }
                            }
                            if (flage) {
                                //要安排的是全天有  没有不能修改的  就删除两条半天的，新增一条全天的
                                List<Long> ids = guideCollarSchedulingList.stream().map(e -> e.getId()).collect(Collectors.toList());
                                if (!flagea && guideCollarSchedulingList != null) {
                                    //这里是多个操作所以记录一份gc备份如果发生错误回滚到这个假期天数
                                    GuideCollar newgc = EntityUtil.copy(gc, GuideCollar.class);
                                    for (int k = 0; k < guideCollarSchedulingList.size(); k++) {
                                        float v = setMinusVacation(req, guideCollarSchedulingList.get(k), gc);
                                        if (v > 0) {
                                            //实际减扣不足跳过这次工作安排
                                            if (!minusVacation(guideCollarSchedulingList.get(k), gc, v)) {
                                                gc = newgc;//回滚到之前的记录
                                                continue out;//有一个不合格就退出外层循环
                                            }
                                        }
                                    }
                                }
                                int delete = baseMapper.deleteBatchIds(ids);
                                if (delete > 0) {
                                    guideCollarScheduling.setSchedulingDate(newDate);
                                    guideCollarScheduling.setId(IdWorker.getId());
                                    if (!flagea) {
                                        //安排成功减扣导领的假期
                                        if (guideCollarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                                            if (!minusVacation(guideCollarScheduling, gc, 1)) {
                                                continue;
                                            }
                                        } else {
                                            if (!minusVacation(guideCollarScheduling, gc, 0.5f)) {
                                                continue;
                                            }
                                        }
                                    }
                                    int insert = baseMapper.insert(guideCollarScheduling);
                                    if (insert < 1) {
                                        return Result.failed(SystemError.CMS_23002);
                                    }
                                } else {
                                    return Result.failed(SystemError.CMS_23002);
                                }
                            } else {
                                //要安排的是全天有不能修改的就失败
                                return Result.failed(SystemError.CMS_23002);
                            }
                        } else {
                            //如果当前请求安排的不为全天只需要找到同为上午或者同为下午的拿一条记录，判断是否有不能改的三种类型，如果不是直接修改
                            //这里是多个操作所以记录一份gc备份如果发生错误回滚到这个假期天数
                            GuideCollar newgc = EntityUtil.copy(gc, GuideCollar.class);
                            for (GuideCollarScheduling item : guideCollarSchedulingList) {
                                //这两条记录只会有一条匹配上
                                if (req.getWorkingHours() == item.getWorkingHours()) {
                                    if (!WORKID1.equals(item.getWorkTypeId()) && !WORKID2.equals(item.getWorkTypeId())
                                            && !WORKID3.equals(item.getWorkTypeId())) {
                                        item.setWorkTypeId(req.getWorkTypeId());
                                        item.setWorkTypeName(req.getWorkTypeName());
                                        item.setRemark(req.getRemark());
                                        if (!flagea) {
                                            float v = setMinusVacation(req, item, gc);
                                            if (v > 0) {
                                                //实际减扣不足跳过这次工作安排
                                                if (!minusVacation(item, gc, v)) {
                                                    gc = newgc;//回滚之前的假期的天数
                                                    continue out;//退出外层循环
                                                }
                                            }
                                        }
                                        count += baseMapper.updateById(item);
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
                if (count == 0) {
                    return Result.failed(SystemError.CMS_23000);
                } else if (count < days) {
                    return Result.success("部分日期不能安排的类型已被跳过！");
                }
            } else {
                int count = 0;
                //安排全部空白日期   这里我们只需要安排空白的
                for (int i = 0; i <= days; i++) {
                    LocalDate newDate = req.getSchedulingDateBegin().plusDays(i);
                    guideCollarScheduling.setSchedulingDate(newDate);
                    QueryWrapper<GuideCollarScheduling> queryWrapper = new QueryWrapper<>();
                    queryWrapper.lambda().eq(GuideCollarScheduling::getIsDeleted, IsDeletedCode.NO.getCode())
                            .eq(GuideCollarScheduling::getGuideCollarId, req.getGuideCollarId())
                            .eq(GuideCollarScheduling::getSchedulingDate, newDate);
                    List<GuideCollarScheduling> guideCollarSchedulingList = baseMapper.selectList(queryWrapper);//这里我们只需要安排空白的（）
                    //如果查到了
                    if (CollectionUtils.isNotEmpty(guideCollarSchedulingList)) {
                        GuideCollarScheduling scheduling = guideCollarSchedulingList.get(0);
                        //这里只需要处理 一条安排and请求安排不能是全天的and这一条记录不能和当前现有记录冲突的and现有安排不能是全天的
                        if (guideCollarSchedulingList.size() == 1
                                && req.getWorkingHours() != scheduling.getWorkingHours()
                                && scheduling.getWorkingHours() != GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()
                                && req.getWorkingHours() != GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                            guideCollarScheduling.setSchedulingDate(newDate);
                            guideCollarScheduling.setId(IdWorker.getId());
                            if (!flagea) {
                                //安排成功减扣导领的假期
                                if (guideCollarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                                    if (!minusVacation(guideCollarScheduling, gc, 1)) {
                                        continue;
                                    }
                                } else {
                                    if (!minusVacation(guideCollarScheduling, gc, 0.5f)) {
                                        continue;
                                    }
                                }
                            }
                            count += baseMapper.insert(guideCollarScheduling);
                        }
                    } else {
                        //如果当天查不到说明安排的是空白的直接新增
                        guideCollarScheduling.setSchedulingDate(newDate);
                        guideCollarScheduling.setId(IdWorker.getId());
                        if (!flagea) {
                            //安排成功减扣导领的假期
                            if (guideCollarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                                if (!minusVacation(guideCollarScheduling, gc, 1)) {
                                    continue;
                                }
                            } else {
                                if (!minusVacation(guideCollarScheduling, gc, 0.5f)) {
                                    continue;
                                }
                            }
                        }
                        count += baseMapper.insert(guideCollarScheduling);
                    }
                }
                if (count == 0) {
                    return Result.failed(SystemError.CMS_23000);
                } else if (count < days) {
                    return Result.success("部分日期已安排或不能安排的类型已被跳过！");
                }
            }
            return Result.success();
        }
        return Result.failed(SystemError.GUIDE_41001);
    }

    /**
     * 被修改假期补偿（工作安排为假期的被修改补偿对应的假期天数）
     * 如果安排的假期是一天被修改的是半天则返回需要减扣的假期天数
     *
     * @Return float 返回可以减扣的天数
     */
    private float setMinusVacation(GuideCollarSchedulingAddReq req, GuideCollarScheduling collarScheduling, GuideCollar gc) {
        float result = 0;
        LocalDate now = LocalDate.now();
        //如果排班日期上的休息时间已经成为了历史那么就不在补偿各种假期天数
        if (!now.plusDays(-1).isAfter(collarScheduling.getSchedulingDate())) {
            return result;
        }
        //排班有关于假期的，就需要抵扣假期   否则直接把被修改的假期补偿成假期天数
        if (req.getWorkTypeId() == WORKID4 || req.getWorkTypeId() == WORKID5 || req.getWorkTypeId() == WORKID6) {
            if (collarScheduling.getWorkTypeId() == WORKID4 && req.getWorkTypeId() == WORKID4) {//月假
                if (req.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                    //请求了一天原有半天需要减扣0.5天
                    if (collarScheduling.getWorkingHours() != GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                        result = 0.5f;
                    }
                } else {
                    //请求了半天原有一天需要加上0.5
                    if (collarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                        gc.setMonthlyLeave(gc.getMonthlyLeave() == null ? 0.5f : gc.getMonthlyLeave() + 0.5f);
                    }
                }
            } else if (collarScheduling.getWorkTypeId() == WORKID5 && req.getWorkTypeId() == WORKID5) {//年假
                if (req.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                    //请求了一天原有半天需要减扣0.5天
                    if (collarScheduling.getWorkingHours() != GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                        result = 0.5f;
                    }
                } else {
                    //请求了半天原有一天需要加上0.5
                    if (collarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                        gc.setAnnualLeave(gc.getAnnualLeave() == null ? 0.5f : gc.getAnnualLeave() + 0.5f);
                    }
                }
            } else if (collarScheduling.getWorkTypeId() == WORKID6 && req.getWorkTypeId() == WORKID6) {//劳假
                if (req.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                    //请求了一天原有半天需要减扣0.5天
                    if (collarScheduling.getWorkingHours() != GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                        result = 0.5f;
                    }
                } else {
                    //请求了半天原有一天需要加上0.5
                    if (collarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                        gc.setLaborLeave(gc.getLaborLeave() == null ? 0.5f : gc.getLaborLeave() + 0.5f);
                    }
                }
            }
        } else {
            //这里只针对 原有假期被修改需要补偿天数
            if (collarScheduling.getWorkTypeId() == WORKID4) {//月假
                //请求了半天原有一天需要加上0.5
                if (collarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                    gc.setMonthlyLeave(gc.getMonthlyLeave() == null ? 1 : gc.getMonthlyLeave() + 1);
                } else {
                    gc.setMonthlyLeave(gc.getMonthlyLeave() == null ? 0.5f : gc.getMonthlyLeave() + 0.5f);
                }
            } else if (collarScheduling.getWorkTypeId() == WORKID5) {//年假
                //请求了半天原有一天需要加上0.5
                if (collarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                    gc.setAnnualLeave(gc.getAnnualLeave() == null ? 1 : gc.getAnnualLeave() + 1);
                } else {
                    gc.setAnnualLeave(gc.getAnnualLeave() == null ? 0.5f : gc.getAnnualLeave() + 0.5f);
                }
            } else if (collarScheduling.getWorkTypeId() == WORKID6) {//劳假
                //请求了半天原有一天需要加上0.5
                if (collarScheduling.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                    gc.setLaborLeave(gc.getLaborLeave() == null ? 1 : gc.getLaborLeave() + 1);
                } else {
                    gc.setLaborLeave(gc.getLaborLeave() == null ? 0.5f : gc.getLaborLeave() + 0.5f);
                }
            }
        }
        return result;
    }

    /**
     * 实际减扣假期
     */
    private boolean minusVacation(GuideCollarScheduling collarScheduling, GuideCollar gc, float day) {
        if (collarScheduling.getWorkTypeId() == WORKID4) {//月假
            if (gc.getMonthlyLeave() != null && gc.getMonthlyLeave() > day) {
                gc.setMonthlyLeave(gc.getMonthlyLeave() - day);
            } else {
                return false;
            }
        } else if (collarScheduling.getWorkTypeId() == WORKID5) {//年假
            if (gc.getAnnualLeave() != null && gc.getAnnualLeave() > day) {
                gc.setAnnualLeave(gc.getAnnualLeave() - day);
            } else {
                return false;
            }
        } else if (collarScheduling.getWorkTypeId() == WORKID6) {//劳假
            if (gc.getLaborLeave() != null && gc.getLaborLeave() > day) {
                gc.setLaborLeave(gc.getLaborLeave() - day);
            } else {
                return false;
            }
        }
        return true;
    }

    /**
     * 查询个人排班
     *
     * @param req
     * @return
     */
    @Override
    public GuideCollarSchedulingQueryDTO query(GuideCollarSchedulingQueryReq req) {
        GuideCollar guideCollar = guideCollarMapper.selectById(req.getGuideCollarId());
        if (guideCollar == null) {
            return null;
        }
        GuideCollarSchedulingQueryDTO guideCollarSchedulingQueryDTO = EntityUtil.copy(guideCollar, GuideCollarSchedulingQueryDTO.class);
        LocalDate contractExpire = guideCollar.getEntryTime().plusYears(guideCollar.getContractPeriod());
        //合同到期日
        guideCollarSchedulingQueryDTO.setContractExpire(contractExpire);
        LocalDate now = LocalDate.now();
        //所在年月第一天和最后一天
        LocalDate firstDay = req.getLocalDate().with(TemporalAdjusters.firstDayOfMonth());
        LocalDate lastDay = req.getLocalDate().with(TemporalAdjusters.lastDayOfMonth());
        int days = Period.between(firstDay, lastDay).getDays();
        //查询月假天数
        GuideCollarMonthlyLeave guideCollarMonthlyLeave = guideCollarMonthlyLeaveMapper.selectByMonthAndId(req.getGuideCollarId(), now);
        guideCollarSchedulingQueryDTO.setMonthlyLeave(guideCollarMonthlyLeave == null ? 0 : guideCollarMonthlyLeave.getMonthlyLeave());
        //封装日数及对应安排
        Map<Integer, List<GuideCollarSchedulingDTO>> listHashMap = new HashMap<>();
        for (int i = 0; i <= days; i++) {
            LocalDate localDate = firstDay.plusDays(i);
            List<GuideCollarScheduling> list = baseMapper.selectListByLocalDateAndCollar(req, localDate);
            if (CollectionUtils.isEmpty(list)) {
                listHashMap.put(i + 1, null);
                continue;
            }
            List<GuideCollarSchedulingDTO> guideCollarSchedulingDTOS = EntityUtil.copyList(list, GuideCollarSchedulingDTO.class);
            listHashMap.put(i + 1, guideCollarSchedulingDTOS);
        }
        guideCollarSchedulingQueryDTO.setGuideCollarSchedulingDTOList(listHashMap);
        return guideCollarSchedulingQueryDTO;
    }

    /**
     * 修改个人排班 弃用
     *
     * @param req
     * @param tokenUser
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result update(GuideCollarSchedulingUpdateReq req, TokenUser tokenUser) {
        GuideCollarScheduling guideCollarScheduling = EntityUtil.copy(req, GuideCollarScheduling.class);
        LocalDateTime now = LocalDateTime.now();
        guideCollarScheduling.setGmtModified(now);
        guideCollarScheduling.setModifiedId(tokenUser.getId());
        int days = Period.between(req.getSchedulingDateBegin(), req.getSchedulingDateEnd()).getDays();
        GuideCollar gc = guideCollarMapper.selectById(req.getGuideCollarId());
        if (gc != null) {
            int workDays = Period.between(gc.getEntryTime(), LocalDate.now()).getDays();
            if (workDays > gc.getContractPeriod() * 365) {
                return Result.failed(SystemError.GUIDE_410011);
            }
            for (int i = 0; i <= days; i++) {
                LocalDate newDate = req.getSchedulingDateBegin().plusDays(i);
                QueryWrapper<GuideCollarScheduling> queryWrapper = new QueryWrapper<>();
                queryWrapper.lambda().eq(GuideCollarScheduling::getSchedulingDate, newDate)
                        .eq(GuideCollarScheduling::getIsDeleted, IsDeletedCode.NO.getCode());
                queryWrapper.lambda().orderByDesc(GuideCollarScheduling::getWorkingHours);
                //获取修改日排班情况
                List<GuideCollarScheduling> guideCollarSchedulingList = baseMapper.selectList(queryWrapper);
                //判断修改日是否排班
                if (CollectionUtils.isEmpty(guideCollarSchedulingList)) {
                    //未排班则直接写入
                    baseMapper.insert(guideCollarScheduling);
                } else {
                    //已排班则遍历待修改日排班
                    Map<Integer, GuideCollarScheduling> map = new HashMap<>();
                    for (GuideCollarScheduling collarScheduling : guideCollarSchedulingList) {
                        //判断是否存在全陪、送团、茶会等工作类型
                        if (WORKID1.equals(collarScheduling.getWorkTypeId())
                                || WORKID2.equals(collarScheduling.getWorkTypeId())
                                || WORKID3.equals(collarScheduling.getWorkTypeId())) {
                            //抛异常回滚
                            throw new BusinessException(SystemError.GUIDE_41001);
                        }
                        map.put(collarScheduling.getWorkingHours(), collarScheduling);
                    }
                    //判断修改日工作类型不为全天且工作类型不为
                    if (guideCollarSchedulingList.size() == 1) {
                        if (map.get(req.getWorkingHours()) != null) {
                            GuideCollarScheduling scheduling = map.get(req.getWorkingHours());
                            if (req.getWorkingHours() == GuideCollarSchedulingWorkHours.ALL_DAY_LONG.getCode()) {
                                guideCollarScheduling.setId(scheduling.getId());
                                baseMapper.updateById(guideCollarScheduling);
                            } else if (req.getWorkingHours() == GuideCollarSchedulingWorkHours.AFTERNOON.getCode()) {
                                guideCollarScheduling.setId(scheduling.getId());
                                baseMapper.updateById(guideCollarScheduling);
                            }
                        } else {
                            baseMapper.insert(guideCollarScheduling);
                        }
                    } else {
                        GuideCollarScheduling scheduling1 = map.get(1);
                        GuideCollarScheduling scheduling2 = map.get(2);
                        if (scheduling1.getWorkingHours() == req.getWorkingHours()) {
                            guideCollarScheduling.setId(scheduling1.getId());
                            baseMapper.updateById(guideCollarScheduling);
                        } else if (scheduling2.getWorkingHours() == req.getWorkingHours()) {
                            guideCollarScheduling.setId(scheduling1.getId());
                            baseMapper.updateById(guideCollarScheduling);
                        } else {
                            baseMapper.updateByLocalDate(newDate, req.getGuideCollarId());
                            baseMapper.insert(guideCollarScheduling);
                        }
                    }
                }
            }
            return Result.success(SystemError.GUIDE_41002);
        }
        return Result.success(SystemError.GUIDE_41001);
    }

    /**
     * 查询排班管理列表
     *
     * @param req
     * @return
     */
    @Override
    public PageResponse<GuideCollarSchedulingListDTO> list(GuideCollarSchedulingListReq req) {
        Page<GuideCollar> page = new Page<>(req.getPageNo(), req.getPageSize());
        QueryWrapper<GuideCollar> guideCollarQueryWrapper = new QueryWrapper<>();
        guideCollarQueryWrapper.lambda().eq(GuideCollar::getType, req.getType())
                .eq(null != req.getDepartmentId(), GuideCollar::getDepartmentId, req.getDepartmentId())
                .eq(req.getCertificatesStatus() != null, GuideCollar::getCertificatesStatus, req.getCertificatesStatus())
                .eq(req.getStatus() != null, GuideCollar::getStatus, req.getStatus())
                .eq(GuideCollar::getIsDeleted, IsDeletedCode.NO.getCode())
                .and(StringUtils.isNotBlank(req.getName()), e ->
                        e.like(GuideCollar::getEmployeeNumber, req.getName())
                                .or().like(GuideCollar::getCnUserName, req.getName())
                );
        Page<GuideCollar> iPage = guideCollarMapper.selectPage(page, guideCollarQueryWrapper);
        List<GuideCollar> records = iPage.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return new PageResponse<>(new ArrayList<>(), iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize());
        }
        List<GuideCollarSchedulingListDTO> listDTOList = EntityUtil.copyList(records, GuideCollarSchedulingListDTO.class);
        for (GuideCollarSchedulingListDTO dto : listDTOList) {
            GuideCollarSchedulingQueryReq queryReq = new GuideCollarSchedulingQueryReq();
            if (null != req.getWorkTypeId()) {
                queryReq.setWorkTypeId(req.getWorkTypeId());
            }
            queryReq.setGuideCollarId(dto.getId());
            queryReq.setLocalDate(req.getLocalDate());
            GuideCollarSchedulingQueryDTO queryDTO = query(queryReq);
            if (queryDTO == null) continue;
            dto.setMonthlyLeave(queryDTO.getMonthlyLeave());
            dto.setGuideCollarSchedulingDTOList(queryDTO.getGuideCollarSchedulingDTOList());
        }
        return new PageResponse<>(listDTOList, iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize());
    }

    /**
     * 批量新增个人排班
     *
     * @param req
     * @param tokenUser
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result addList(GuideCollarSchedulingAddListReq req, TokenUser tokenUser) {
        GuideCollarSchedulingAddReq guideCollarSchedulingAddReq = EntityUtil.copy(req, GuideCollarSchedulingAddReq.class);
        for (GuideCollarSchedulingReq guideCollarSchedulingReq : req.getGuideCollar()) {
            guideCollarSchedulingAddReq.setGuideCollarId(guideCollarSchedulingReq.getGuideCollarId());
            guideCollarSchedulingAddReq.setGuideCollarName(guideCollarSchedulingReq.getGuideCollarName());
            add(guideCollarSchedulingAddReq, tokenUser, false);
        }
        return Result.success();
    }

    /**
     * 批量编辑个人排班
     *
     * @param req
     * @param tokenUser
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateList(GuideCollarSchedulingUpdateListReq req, TokenUser tokenUser) {
        GuideCollarSchedulingUpdateReq guideCollarSchedulingUpdateReq = EntityUtil.copy(req, GuideCollarSchedulingUpdateReq.class);
        for (GuideCollarSchedulingReq guideCollarSchedulingReq : req.getGuideCollar()) {
            guideCollarSchedulingUpdateReq.setGuideCollarId(guideCollarSchedulingReq.getGuideCollarId());
            guideCollarSchedulingUpdateReq.setGuideCollarName(guideCollarSchedulingReq.getGuideCollarName());
            update(guideCollarSchedulingUpdateReq, tokenUser);
        }
        return Result.success();
    }

    @Override
    public List<GuideCollarSchedulingExcelDTO> selectListByIds(GuideCollarSchedulingListExcelReq req) {
        LocalDate firstDay = req.getLocalDate().with(TemporalAdjusters.firstDayOfMonth());
        LocalDate lastDay = req.getLocalDate().with(TemporalAdjusters.lastDayOfMonth());
        int days = Period.between(firstDay, lastDay).getDays();
        ArrayList<GuideCollarSchedulingExcelDTO> guideCollarSchedulingExcelDTOS = new ArrayList<>();
        List<GuideCollar> guideCollars = guideCollarMapper.selectBatchIds(req.getIdList());
        if (CollectionUtils.isEmpty(guideCollars)) {
            return new ArrayList<>();
        }
        for (GuideCollar guideCollar : guideCollars) {
            GuideCollarSchedulingExcelDTO excelDTO = EntityUtil.copy(guideCollar, GuideCollarSchedulingExcelDTO.class);
            GuideCollarSchedulingQueryReq queryReq = new GuideCollarSchedulingQueryReq();
            if (null != req.getWorkTypeId()) {
                queryReq.setWorkTypeId(req.getWorkTypeId());
            }
            queryReq.setGuideCollarId(guideCollar.getId());
            queryReq.setLocalDate(req.getLocalDate());
            GuideCollarSchedulingQueryDTO queryDTO = query(queryReq);
            if (queryDTO == null) continue;
            GuideCollarSchedulingExcelDTO schedulingExcelDTO = EntityUtil.copy(queryDTO, GuideCollarSchedulingExcelDTO.class);
            schedulingExcelDTO.setGender(Gender.getMsg(queryDTO.getGender()));
            schedulingExcelDTO.setRowDate1(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(1)));
            schedulingExcelDTO.setRowDate1(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(2)));
            schedulingExcelDTO.setRowDate2(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(3)));
            schedulingExcelDTO.setRowDate3(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(4)));
            schedulingExcelDTO.setRowDate4(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(5)));
            schedulingExcelDTO.setRowDate5(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(6)));
            schedulingExcelDTO.setRowDate6(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(7)));
            schedulingExcelDTO.setRowDate7(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(8)));
            schedulingExcelDTO.setRowDate8(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(9)));
            schedulingExcelDTO.setRowDate9(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(10)));
            schedulingExcelDTO.setRowDate10(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(11)));
            schedulingExcelDTO.setRowDate11(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(12)));
            schedulingExcelDTO.setRowDate12(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(13)));
            schedulingExcelDTO.setRowDate13(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(14)));
            schedulingExcelDTO.setRowDate14(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(15)));
            schedulingExcelDTO.setRowDate15(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(16)));
            schedulingExcelDTO.setRowDate16(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(17)));
            schedulingExcelDTO.setRowDate17(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(18)));
            schedulingExcelDTO.setRowDate18(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(19)));
            schedulingExcelDTO.setRowDate19(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(20)));
            schedulingExcelDTO.setRowDate20(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(21)));
            schedulingExcelDTO.setRowDate21(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(22)));
            schedulingExcelDTO.setRowDate22(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(23)));
            schedulingExcelDTO.setRowDate23(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(24)));
            schedulingExcelDTO.setRowDate24(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(25)));
            schedulingExcelDTO.setRowDate25(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(26)));
            schedulingExcelDTO.setRowDate26(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(26)));
            schedulingExcelDTO.setRowDate27(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(27)));
            schedulingExcelDTO.setRowDate28(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(28)));
            if (days + 1 >= 29) {
                schedulingExcelDTO.setRowDate29(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(29)));
            } else {
                schedulingExcelDTO.setRowDate29("");
            }
            if (days + 1 >= 30) {
                schedulingExcelDTO.setRowDate30(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(30)));
            } else {
                schedulingExcelDTO.setRowDate30("");
            }
            if (days + 1 >= 30) {
                schedulingExcelDTO.setRowDate31(getToString(queryDTO.getGuideCollarSchedulingDTOList().get(31)));
            } else {
                schedulingExcelDTO.setRowDate31("");
            }
            guideCollarSchedulingExcelDTOS.add(schedulingExcelDTO);
        }
        return guideCollarSchedulingExcelDTOS;
    }

    @Override
    public Result delete(Long gcsId, TokenUser tokenUser) {
        GuideCollarScheduling gcs = baseMapper.selectById(gcsId);
        GuideCollar gc = guideCollarMapper.selectById(gcs.getGuideCollarId());
        if (gcs != null && gc != null) {
            GuideCollarSchedulingAddReq gcsa = new GuideCollarSchedulingAddReq();
            gcsa.setWorkTypeId(WORKID3); //设置一个非假期类型 不走抵扣逻辑
            float result = setMinusVacation(gcsa, gcs, gc);
            if (result == 0) {
                gc.setGmtModified(LocalDateTime.now());
                gc.setModifiedId(tokenUser.getId());
                int i = guideCollarMapper.updateById(gc);
                if (i > 0) {
                    int delete = baseMapper.deleteById(gcs.getId());
                    if (delete > 0) {
                        return Result.success();
                    }
                }
            }
        }
        return Result.failed(SystemError.GUIDE_41006);
    }

    private String getToString(List<GuideCollarSchedulingDTO> guideCollarSchedulingDTOS) {
        if (guideCollarSchedulingDTOS.size() == 0) {
            return null;
        } else {
            String name = "";
            for (int i = 0; i < guideCollarSchedulingDTOS.size(); i++) {
                name = name + guideCollarSchedulingDTOS.get(i).getWorkTypeName() + "|";
            }
            return name.substring(0, name.length() - 1);
        }
    }


}
